Getting closer to updating the treemenu view properly from the model signals
authorTristan Van Berkom <tristan.van.berkom@gmail.com>
Wed, 24 Nov 2010 11:00:10 +0000 (20:00 +0900)
committerTristan Van Berkom <tristan.van.berkom@gmail.com>
Tue, 4 Jan 2011 14:37:08 +0000 (23:37 +0900)
gtk/gtktreemenu.c
tests/testcombo.c

index db970c99ffb9dc82c45885c5cc40a18f006c457e..e9d63514e8cb82f9d060148a67e8b9d75f3f481b 100644 (file)
@@ -78,6 +78,9 @@ static void       gtk_tree_menu_populate                      (GtkTreeMenu
 static GtkWidget *gtk_tree_menu_create_item                   (GtkTreeMenu          *menu,
                                                               GtkTreeIter          *iter,
                                                               gboolean              header_item);
+static void       gtk_tree_menu_create_submenu                (GtkTreeMenu          *menu,
+                                                              GtkWidget            *item,
+                                                              GtkTreePath          *path);
 static void       gtk_tree_menu_set_area                      (GtkTreeMenu          *menu,
                                                               GtkCellArea          *area);
 static GtkWidget *gtk_tree_menu_get_path_item                 (GtkTreeMenu          *menu,
@@ -618,8 +621,17 @@ gtk_tree_menu_get_path_item (GtkTreeMenu          *menu,
          GtkTreeRowReference *row =
            g_object_get_qdata (G_OBJECT (child), tree_menu_path_quark);
 
-         if (row && gtk_tree_row_reference_valid (row))
-           path = gtk_tree_row_reference_get_path (row);
+         if (row)
+           {
+             path = gtk_tree_row_reference_get_path (row);
+             
+             if (!path)
+               /* Return any first child where it's row-reference became invalid,
+                * this is because row-references get null paths before we recieve
+                * the "row-deleted" signal.
+                */
+               item = child;
+           }
        }
       else
        {
@@ -628,6 +640,13 @@ gtk_tree_menu_get_path_item (GtkTreeMenu          *menu,
          /* It's always a cellview */
          if (GTK_IS_CELL_VIEW (view))
            path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (view));
+
+         if (!path)
+           /* Return any first child where it's row-reference became invalid,
+            * this is because row-references get null paths before we recieve
+            * the "row-deleted" signal.
+            */
+           item = child;
        }
 
       if (path)
@@ -650,43 +669,97 @@ gtk_tree_menu_path_in_menu (GtkTreeMenu  *menu,
                            gboolean     *header_item)
 {
   GtkTreeMenuPrivate *priv = menu->priv;
-  GtkTreePath        *parent_path = gtk_tree_path_copy (path);
   gboolean            in_menu = FALSE;
   gboolean            is_header = FALSE;
 
   /* Check if the is in root of the model */
-  if (gtk_tree_path_get_depth (parent_path) == 1)
+  if (gtk_tree_path_get_depth (path) == 1)
     {
       if (!priv->root)
-       in_menu = TRUE;
+       {
+         g_print ("gtk_tree_menu_path_in_menu: Found in root menu !\n");
+         in_menu = TRUE;
+       }
     }
   /* If we are a submenu, compare the parent path */
-  else if (priv->root && gtk_tree_path_up (parent_path))
+  else if (priv->root && gtk_tree_path_get_depth (path) > 1)
     {
-      GtkTreePath *root_path =
-       gtk_tree_row_reference_get_path (priv->root);
+      GtkTreePath *root_path   = gtk_tree_row_reference_get_path (priv->root);
+      GtkTreePath *parent_path = gtk_tree_path_copy (path);
+
+      gtk_tree_path_up (parent_path);
 
       if (gtk_tree_path_compare (root_path, parent_path) == 0)
-       in_menu = TRUE;
+       {
+         in_menu = TRUE;
+         g_print ("gtk_tree_menu_path_in_menu: Found in this menu !\n");
+       }
 
       if (!in_menu && priv->menu_with_header && 
          gtk_tree_path_compare (root_path, path) == 0)
        {
+         g_print ("gtk_tree_menu_path_in_menu: Found as menu header !\n");
          in_menu   = TRUE;
          is_header = TRUE;
        }
-
       gtk_tree_path_free (root_path);
+      gtk_tree_path_free (parent_path);
     }
 
-  gtk_tree_path_free (parent_path);
-
   if (header_item)
     *header_item = is_header;
 
   return in_menu;
 }
 
+static GtkWidget *
+gtk_tree_menu_path_needs_submenu (GtkTreeMenu *menu, 
+                                 GtkTreePath *search)
+{
+  GtkWidget   *item = NULL;
+  GList       *children, *l;
+  GtkTreePath *parent_path;
+
+  if (gtk_tree_path_get_depth (search) <= 1)
+    return NULL;
+
+  parent_path = gtk_tree_path_copy (search);
+  gtk_tree_path_up (parent_path);
+
+  children    = gtk_container_get_children (GTK_CONTAINER (menu));
+
+  for (l = children; item == NULL && l != NULL; l = l->next)
+    {
+      GtkWidget   *child = l->data;
+      GtkTreePath *path  = NULL;
+
+      /* Separators dont get submenus, if it already has a submenu then let
+       * the submenu handle inserted rows */
+      if (!GTK_IS_SEPARATOR_MENU_ITEM (child) && 
+         !gtk_menu_item_get_submenu (GTK_MENU_ITEM (child)))
+       {
+         GtkWidget *view = gtk_bin_get_child (GTK_BIN (child));
+
+         /* It's always a cellview */
+         if (GTK_IS_CELL_VIEW (view))
+           path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (view));
+       }
+
+      if (path)
+       {
+         if (gtk_tree_path_compare (parent_path, path) == 0)
+           item = child;
+
+         gtk_tree_path_free (path);
+       }
+    }
+
+  g_list_free (children);
+  gtk_tree_path_free (parent_path);
+
+  return item;
+}
+
 static void
 row_inserted_cb (GtkTreeModel     *model,
                 GtkTreePath      *path,
@@ -695,11 +768,11 @@ row_inserted_cb (GtkTreeModel     *model,
 {
   GtkTreeMenuPrivate *priv = menu->priv;
   gint               *indices, index, depth;
+  GtkWidget          *item;
 
   /* If the iter should be in this menu then go ahead and insert it */
   if (gtk_tree_menu_path_in_menu (menu, path, NULL))
     {
-      GtkWidget *item;
 
       if (priv->wrap_width > 0)
        rebuild_menu (menu);
@@ -728,6 +801,19 @@ row_inserted_cb (GtkTreeModel     *model,
          gtk_cell_area_context_flush (menu->priv->context);
        }
     }
+  else
+    {
+      /* Create submenus for iters if we need to */
+      item = gtk_tree_menu_path_needs_submenu (menu, path);
+      if (item)
+       {
+         GtkTreePath *item_path = gtk_tree_path_copy (path);
+
+         gtk_tree_path_up (item_path);
+         gtk_tree_menu_create_submenu (menu, item, item_path);
+         gtk_tree_path_free (item_path);
+       }
+    }
 }
 
 static void
@@ -737,29 +823,25 @@ row_deleted_cb (GtkTreeModel     *model,
 {
   GtkTreeMenuPrivate *priv = menu->priv;
   GtkWidget          *item;
-  gboolean            header_item;
-  gboolean            in_menu;
-
-  in_menu = gtk_tree_menu_path_in_menu (menu, path, &header_item);
 
   /* If it's the header item we leave it to the parent menu 
    * to remove us from its menu
    */
-  if (!header_item && in_menu)
+  item = gtk_tree_menu_get_path_item (menu, path);
+
+  g_print ("Deleting item %p\n", item);
+
+  if (item)
     {
-      item = gtk_tree_menu_get_path_item (menu, path);
-      if (item)
+      if (priv->wrap_width > 0)
+       rebuild_menu (menu);
+      else
        {
-         if (priv->wrap_width > 0)
-           rebuild_menu (menu);
-         else
-           {
-             /* Get rid of the deleted item */
-             gtk_widget_destroy (item);
-             
-             /* Resize everything */
-             gtk_cell_area_context_flush (menu->priv->context);
-           }
+         /* Get rid of the deleted item */
+         gtk_widget_destroy (item);
+         
+         /* Resize everything */
+         gtk_cell_area_context_flush (menu->priv->context);
        }
     }
 }
@@ -1082,6 +1164,41 @@ relayout_item (GtkTreeMenu *menu,
                    current_row, current_row + rows);
 }
 
+static void
+gtk_tree_menu_create_submenu (GtkTreeMenu *menu,
+                             GtkWidget   *item,
+                             GtkTreePath *path)
+{
+  GtkTreeMenuPrivate *priv = menu->priv;
+  GtkWidget          *view;
+  GtkWidget          *submenu;
+
+  view = gtk_bin_get_child (GTK_BIN (item));
+  gtk_cell_view_set_draw_sensitive (GTK_CELL_VIEW (view), TRUE);
+
+  submenu = gtk_tree_menu_new_with_area (priv->area);
+
+  gtk_tree_menu_set_row_separator_func (GTK_TREE_MENU (submenu), 
+                                       priv->row_separator_func,
+                                       priv->row_separator_data,
+                                       priv->row_separator_destroy);
+  gtk_tree_menu_set_header_func (GTK_TREE_MENU (submenu), 
+                                priv->header_func,
+                                priv->header_data,
+                                priv->header_destroy);
+
+  gtk_tree_menu_set_wrap_width (GTK_TREE_MENU (submenu), priv->wrap_width);
+  gtk_tree_menu_set_row_span_column (GTK_TREE_MENU (submenu), priv->row_span_col);
+  gtk_tree_menu_set_column_span_column (GTK_TREE_MENU (submenu), priv->col_span_col);
+  
+  gtk_tree_menu_set_model_internal (GTK_TREE_MENU (submenu), priv->model);
+  gtk_tree_menu_set_root (GTK_TREE_MENU (submenu), path);
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+  
+  g_signal_connect (submenu, "menu-activate", 
+                   G_CALLBACK (submenu_activated_cb), menu);
+}
+
 static GtkWidget *
 gtk_tree_menu_create_item (GtkTreeMenu *menu,
                           GtkTreeIter *iter,
@@ -1127,27 +1244,7 @@ gtk_tree_menu_create_item (GtkTreeMenu *menu,
       /* Add a GtkTreeMenu submenu to render the children of this row */
       if (header_item == FALSE &&
          gtk_tree_model_iter_has_child (priv->model, iter))
-       {
-         GtkWidget           *submenu;
-
-         submenu = gtk_tree_menu_new_with_area (priv->area);
-
-         gtk_tree_menu_set_row_separator_func (GTK_TREE_MENU (submenu), 
-                                               priv->row_separator_func,
-                                               priv->row_separator_data,
-                                               priv->row_separator_destroy);
-         gtk_tree_menu_set_header_func (GTK_TREE_MENU (submenu), 
-                                        priv->header_func,
-                                        priv->header_data,
-                                        priv->header_destroy);
-
-         gtk_tree_menu_set_model_internal (GTK_TREE_MENU (submenu), priv->model);
-         gtk_tree_menu_set_root (GTK_TREE_MENU (submenu), path);
-         gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
-
-         g_signal_connect (submenu, "menu-activate", 
-                           G_CALLBACK (submenu_activated_cb), menu);
-       }
+       gtk_tree_menu_create_submenu (menu, item, path);
     }
 
   gtk_tree_path_free (path);
index f321fb0a55d220cb665520183f291c6ffa294a10..1de03fc79db42fd53310e54faf5b7fd406736db0 100644 (file)
@@ -1092,6 +1092,7 @@ main (int argc, char **argv)
         g_object_set (renderer, "text", "la la la", NULL);
         gtk_container_add (GTK_CONTAINER (boom), cellview);
 
+#if 0
         /* GtkComboBox list */
         tmp = gtk_frame_new ("GtkComboBox (list)");
         gtk_box_pack_start (GTK_BOX (mainbox), tmp, FALSE, FALSE, 0);
@@ -1333,7 +1334,7 @@ main (int argc, char **argv)
                                         NULL);
        
         gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0);
-
+#endif
 
         /* Capitals */
         tmp = gtk_frame_new ("Where are you ?");
@@ -1368,6 +1369,7 @@ main (int argc, char **argv)
        gdk_threads_add_timeout (1000, (GSourceFunc) capital_animation, model);
 #endif
 
+#if 0
        /* Ellipsizing growing combos */
         tmp = gtk_frame_new ("Unconstrained Menu");
         gtk_box_pack_start (GTK_BOX (mainbox), tmp, FALSE, FALSE, 0);
@@ -1388,7 +1390,7 @@ main (int argc, char **argv)
                                         "text", 0, NULL);
         gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0);
        gtk_combo_box_set_popup_fixed_width (GTK_COMBO_BOX (combobox), FALSE);
-
+#endif
         gtk_widget_show_all (window);
 
         gtk_main ();